package com.apes.scm.account.account.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.query.QueryService;
import com.apes.framework.rop.context.RopContextHolder;
import com.apes.framework.util.Arith;
import com.apes.framework.util.DateUtil;
import com.apes.framework.util.MapUtil;
import com.apes.hr.area.model.DeptAreaItem;
import com.apes.hr.area.repository.DeptAreaItemRepository;
import com.apes.pi.service.PiManager;
import com.apes.scm.account.account.model.InventoryBatch;
import com.apes.scm.account.account.model.InventoryMode;
import com.apes.scm.account.account.model.Stock;
import com.apes.scm.account.account.repository.InventoryBatchRepository;
import com.apes.scm.account.account.repository.StockRepository;
import com.apes.scm.account.method.Batch;
import com.apes.scm.account.method.BatchMethod;
import com.apes.scm.contract.model.Contract;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.frame.repository.DeptRepository;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.masterdata.party.service.PartyRoleService;
import com.apes.scm.masterdata.product.model.Product;
import com.apes.scm.masterdata.product.model.ProductGroup;
import com.apes.scm.masterdata.product.repository.ProductGroupRepository;
import com.apes.scm.masterdata.product.repository.ProductRepository;
import com.apes.scm.masterdata.product.service.CategorySupplyRangeService;
import com.apes.scm.masterdata.stock.model.Location;
import com.apes.scm.masterdata.stock.repository.LocationRepository;
import com.apes.scm.pur.purchaseOrder.model.PurchaseOrder;
import com.apes.scm.pur.purchaseOrder.repository.PurchaseOrderRepository;
import com.apes.scm.pur.purchaseReturn.model.PurchaseReturn;
import com.apes.scm.pur.purchaseReturn.repository.PurchaseReturnRepository;
import com.apes.scm.rbac.model.Post;
import com.apes.scm.rbac.repository.PostRepository;
import com.apes.scm.voucher.model.Voucher;
import com.apestech.framework.web.lib.ResponseWriter;
import lombok.Data;
import org.hibernate.query.internal.NativeQueryImpl;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;

@Service("stockService")
public class StockService extends DomainService {

    @Autowired
    private PiManager piManager;
    @Autowired
    private DeptRepository deptRepository;

    @Autowired
    private StockRepository stockRepository;

    @Autowired
    private ProductAccountService productAccountService;

    @Value("${apes.switched:false}")
    private Boolean switched;

    public static final String CONST_FNCOMMUNALSERVICE_PLATFORM_1001 = "1001";
    public static final String CONST_FNCOMMUNALSERVICE_PLATFORM_1007 = "1007";
    /***
     * 查询库存包括集群和赋能
     */
    public Map queryAll(SimpleRequest request) {
        JSONObject returnJson = new JSONObject();
        Map condition = parseCondition(request);

        if ("Fn".equals(condition.get("BELONG"))) {
            return request.getMap();
        } else {
            final ResponseWriter[] writer = {null};
            HttpServletResponse response = (HttpServletResponse) RopContextHolder.get().getRawResponseObject();
            writer[0] = new ResponseWriter(response);
            writer[0].setSysid("ESB");
            try {
                condition.remove("BELONG");
                condition.put("PAGE", request.get("page"));
                condition.put("SIZE", request.get("size"));
                returnJson = queryJeKunStock(condition);
                com.apestech.framework.json.JSONObject param = new com.apestech.framework.json.JSONObject();
                param.put("page", returnJson.get("page"));
                param.put("elements", returnJson.get("elements"));
                param.put("size", returnJson.get("size"));
                param.put("pages", returnJson.get("pages"));
                param.put("total", returnJson.get("total"));
                writer[0].writeJSONDetail("true", "成功", param, null, new com.apestech.framework.json.JSONArray(returnJson.getJSONArray("content")));
            } catch (Exception e) {
                try {
                    writer[0].writeError("writeWeb", "WEB写数失败");
                } catch (Exception e1) {
                    throw new RuntimeException(e);
                }
            }
        }
        return returnJson;
    }

    // 查询赋能库存
    private void queryFnStock(SimpleRequest request) {
        SpringManager.getBean(QueryService.class).query(request);
    }

    // 查询集群库存
    private JSONObject queryJeKunStock(Map condition) {
        JSONObject responseJson = piManager.synErp("masterDataConversionService.queryKCS", condition);

        if (responseJson != null && responseJson.getString("obj") != null) {
            responseJson = JSONObject.parseObject(responseJson.getString("obj"));
        }

        return responseJson;
    }

    /***
     * 解析条件
     */
    private Map parseCondition(SimpleRequest request) {
        JSONArray condition = request.getJO().getJSONArray("condition");
        Map returnMap = new HashMap();
        String BELONG = "";
        for (Object o : condition) {
            JSONObject obj = (JSONObject) o;
            if ("BELONG".equals(obj.getString("field")))
                BELONG = obj.getString("value");
        }
        String finalBELONG = BELONG;
        condition.stream().forEach(json -> {
            JSONObject obj = (JSONObject) json;
            if ("DEPT_REGION".equals(obj.getString("field"))) {
                List<String> value = obj.getJSONArray("value").toJavaList(String.class);
                List<DeptAreaItem> deptAreaItems = SpringManager.getBean(DeptAreaItemRepository.class).findByDeptAreaIn(value);
                JSONArray deptIds = new JSONArray();
                for (DeptAreaItem deptAreaItem : deptAreaItems) {
                    deptIds.add(deptAreaItem.getDept().getId());
                }
                obj.put("value", deptIds);
                deptIds = new JSONArray();
                for (DeptAreaItem deptAreaItem : deptAreaItems) {
                    deptIds.add(deptAreaItem.getDept().getOrigin());
                }
                if (!finalBELONG.equals("Fn"))
                    obj.put("value", deptIds);
            }
            if (obj.getString("type") == null) {
                returnMap.put(obj.getString("field"), obj.getString("value"));
            } else if (obj.getString("type").equals("date") && obj.getString("operator").equals("GTE")) {
                returnMap.put(obj.getString("field") + "_START", DateUtil.parse(obj.getString("value"), DateUtil.SHOW_DATETIME_FORMAT));
            } else if (obj.getString("type").equals("date") && obj.getString("operator").equals("LTE")) {
                returnMap.put(obj.getString("field") + "_END", DateUtil.parse(obj.getString("value"), DateUtil.SHOW_DATETIME_FORMAT));
            } else if (obj.getString("type").equals("date") && obj.getString("operator").equals("EQ")) {
                returnMap.put(obj.getString("field"), DateUtil.parse(obj.getString("value")));
            }
        });
        returnMap.put("SIZE", request.get("size"));
        returnMap.put("PAGE", request.get("page"));
        return returnMap;
    }

    /**
     * 平台参考价
     *
     * @param simpleRequest
     */
    public void queryPlatformReferenceePrice(SimpleRequest simpleRequest) {
        JSONObject param = new JSONObject();
        JSONArray condition_Array = JSON.parseObject(simpleRequest.getData().toString()).getJSONArray("condition");
        Dept dept = new Dept();
        for (int i = 0, iLen = condition_Array.size(); i < iLen; i++) {
            JSONObject condition_Obj = condition_Array.getJSONObject(i);

            if ("DEPT_ID".equals(condition_Obj.getString("field"))) {
                dept = deptRepository.findOne(condition_Obj.getString("value"));
                param.put(condition_Obj.getString("field"), dept.getOrigin());
            } else {
                param.put(condition_Obj.getString("field"), condition_Obj.get("value"));
            }
        }
        JSONObject getResult = piManager.synErp("masterDataConversionService.qryPTCGCKJ", param);
        JSONObject getObj = JSONObject.parseObject(getResult.getString("obj"));
        if (getObj.getJSONArray("content").size() == 0) {
            throw new RuntimeException("该商品无库存, 无法提供平台采购参考价!");
        }
        getObj.getJSONArray("content").getJSONObject(0).put("DEPT_ID", "[" + dept.getId() + "]" + dept.getName());

        final ResponseWriter[] writer = {null};
        HttpServletResponse response = (HttpServletResponse) RopContextHolder.get().getRawResponseObject();
        writer[0] = new ResponseWriter(response);
        writer[0].setSysid("ESB");
        try {
            com.apestech.framework.json.JSONObject returnParam = new com.apestech.framework.json.JSONObject();
            returnParam.put("page", getObj.get("page"));
            returnParam.put("size", getObj.get("size"));
            returnParam.put("total", getObj.get("total"));
            writer[0].writeJSONDetail("true", "成功", returnParam, null, new com.apestech.framework.json.JSONArray(getObj.getJSONArray("content")));
        } catch (Exception e) {
            try {
                writer[0].writeError("writeWeb", "该商品无库存, 无法提供平台采购参考价!");
            } catch (Exception e1) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 计算仓库库存价值
     **/
    public Map calcStockOfInventory(SimpleRequest request) {
        String locationId = request.get("locationId"); //源
        String toLocationId = request.get("toLocationId"); //目的
        Location toLocation = SpringManager.getBean(LocationRepository.class).findOne(toLocationId);
        if (toLocation == null) {
            throw new RuntimeException("转入仓库输入错误！");
        }

        Dept dept = SpringManager.getBean(DeptRepository.class).findAll(JpaDsl.toCriteriaByEq("company", toLocation.getCompany(), "deptType.id", "000006")).stream().findFirst().orElse(null);
        if (dept == null) {
            throw new RuntimeException("请先定义采购部门！");
        }


        List<StockInventory> stockInventories = new ArrayList<>();
        stockRepository.findStockByLocation(locationId).forEach(stock -> new BatchMethod<Batch>() {
            @Override
            public Iterable<Batch> wrap() {
                return findInventoryBatch(stock.getLocation().getCompany().getId(), stock.getLocation().getId(), stock.getProduct().getId());
            }

            @Override
            public void succeed(Batch batch, double increment) {
                StockInventory stockInventory = new StockInventory();
                stockInventory.setStock(stock);
                stockInventory.setInventoryBatch((InventoryBatch) batch.getEntity());
                stockInventory.setIncrement(increment);
                stockInventories.add(stockInventory);
            }

            @Override
            public void error(double surplus) {
                throw new RuntimeException("商品：["+stock.getProduct().getId()+"]" + stock.getProduct().getId() + " 价值库存数量少 " + surplus + "！");
            }
        }.execute(stock.getCustodyQty()));

        stockInventories.stream().collect(groupingBy(StockInventory::getSupplier)).forEach((supplier, v) -> {
            if ("A1001".equals(supplier.getId())) {/**调拨**/
                makeCrossCompanyTransfer(locationId, toLocationId, supplier, v);
            } else { /**返厂-> 采购**/
                v.stream().collect(groupingBy(StockInventory::getContract)).forEach((contract, v1) -> {
                    if (v1.isEmpty()) return;

                    /**返厂**/
                    makePurchaseReturn(supplier, contract, v1);

                    /**采购**/
                    makePurchaseOrder(toLocation, dept, supplier, contract, v1);
                });
            }
        });
        return new HashMap();
    }

    private void makeCrossCompanyTransfer(String locationId, String toLocationId, PartyRole supplier, List<StockInventory> v) {
        Object crossCompanyTransfer = invoke("cross.company.transfer.save", mapper(
                "company", mapper("id", v.get(0).getStock().getCompany().getId()),
                "shipLocation", mapper("id", locationId),
                "receiptLocation", mapper("id", toLocationId),
                "returnReason", mapper("id", "001381"),
                "transferType", mapper("id", "000159"),
                "note", "门店批量库存处理",
                "crossCompanyTransferItems", v.stream().map(sockInventory -> {
                    Map m = new HashMap();
                    m.put("product", mapper("id", sockInventory.getInventoryBatch().getProduct().getId()));
                    m.put("tax", mapper("id", sockInventory.getInventoryBatch().getTax().getId()));
                    m.put("uom", mapper("id", sockInventory.getInventoryBatch().getUom().getId()));
                    m.put("priceUnit", sockInventory.getInventoryBatch().getTaxCostPrice());
                    m.put("productReturnQty", sockInventory.getIncrement());
                    m.put("productSumQty", sockInventory.getIncrement());
                    m.put("supplier", mapper("id", supplier.getId()));
                    m.put("inventoryBatch", mapper("id", sockInventory.getInventoryBatch().getId()));
                    return m;
                }).collect(Collectors.toList())));
        invoke("cross.company.transfer.approve", crossCompanyTransfer);
    }

    private void makePurchaseReturn(PartyRole supplier, Contract contract, List<StockInventory> v1) {
        PartyRole employee = SpringManager.getBean(PartyRoleService.class).findByPartyAndRole(1, "Employee");
        Enumeration moveType = new Enumeration();
        moveType.setId("one");

        PurchaseReturn purchaseReturn = invoke("purchase.return.create1", mapper(
                "company", mapper("id", v1.get(0).getStock().getCompany().getId()),
                "dept", mapper("id", v1.get(0).getInventoryBatch().getDept().getId()),
                "clerk", mapper("id", contract.getApproveUid().getId()),
                "supplier", mapper("id", supplier.getId()),
                "contract", mapper("id", contract.getId()),
                "cooperation", mapper("id", contract.getCooperation().getId()),
                "moveType", mapper("id", moveType.getId()),
                "location", mapper("id", v1.get(0).getStock().getLocation().getId()),
                "note", "门店批量库存处理",
                "purchaseReturnItems", v1.stream().map(sockInventory -> {
                    Map m = new HashMap();
                    m.put("product", mapper("id", sockInventory.getInventoryBatch().getProduct().getId()));
                    m.put("tax", mapper("id", sockInventory.getInventoryBatch().getTax().getId()));
                    m.put("inventoryBatch", mapper("id", sockInventory.getInventoryBatch().getId()));
                    m.put("uom", mapper("id", sockInventory.getInventoryBatch().getUom().getId()));
                    m.put("productSumQty", sockInventory.getIncrement());
                    m.put("priceUnit", sockInventory.getInventoryBatch().getTaxCostPrice());
                    m.put("productReturnQty", sockInventory.getIncrement());
                    return m;
                }).collect(Collectors.toList())));

        purchaseReturn.setState("approve");
        purchaseReturn.setApproveUid(employee);
        purchaseReturn.setDateApprove(new Date());

        purchaseReturn.getPurchaseReturnItems().forEach(item -> {
            productAccountService.setProductCustody(item.getProduct(), item.getPurchaseReturn().getLocation(),
                    item.getUom(), -1 * Math.abs(item.getProductReturnQty()),
                    item.getPurchaseReturn().getInnerBusinessType(), item.getPurchaseReturn().getInnerBusinessKey(),
                    String.valueOf(item.getId()), item.getPurchaseReturn().getNote(), item.getPurchaseReturn().getCompany());
            item.delivery(item.getProductReturnQty());
        });
        purchaseReturn.setShipped();
        purchaseReturn = SpringManager.getBean(PurchaseReturnRepository.class).saveAndFlush(purchaseReturn);

        Voucher voucher = invoke("voucher.create", mapper(
                "company", mapper("id", purchaseReturn.getCompany().getId()),
                "dept", mapper("id", purchaseReturn.getDept().getId()),
                "clerk", mapper("id", purchaseReturn.getClerk().getId()),
                "contract", purchaseReturn.getContract() != null ? mapper("id", purchaseReturn.getContract().getId()) : new HashMap<>(),
//                "contract", mapper("id",contract.getId()),
                "partner", mapper("id", purchaseReturn.getSupplier().getId()),
                "inventoryMode", purchaseReturn.getCooperation().getInventoryMode(),
                "accountingMethod", purchaseReturn.getCooperation().getAccountingMethod(),
                "origin", purchaseReturn.getId(),
                "originBusinessType", purchaseReturn.getInnerBusinessType(),
                "source", purchaseReturn.getId(),
                "sourceBusinessType", purchaseReturn.getInnerBusinessType(),
                "returned", true,
                "voucherItems", purchaseReturn.getPurchaseReturnItems().stream().map(item -> {
                    Map m = new HashMap();
                    m.put("product", mapper("id", item.getProduct().getId()));
                    m.put("tax", mapper("id", item.getTax().getId()));
                    m.put("owner", mapper("id", item.getPurchaseReturn().getLocation().getCompany().getId()));
                    m.put("uom", mapper("id", item.getUom().getId()));
                    m.put("productQty", -1 * Math.abs(item.getProductReturnQty()));
                    m.put("priceUnit", item.getPriceUnit());
                    m.put("originItemId", String.valueOf(item.getId()));
                    m.put("sourceItemId", String.valueOf(item.getId()));
                    m.put("inventoryBatch", mapper("id", item.getInventoryBatch().getId()));
                    return m;
                }).collect(Collectors.toList())
        ));

        if (!("A00000".equals(supplier.getId())) && InventoryMode.IM_OWN.equals(voucher.getInventoryMode())) { /**生成帐单**/
            invoke("invoice.create", MapUtil.mapped(invoke("voucher.flow.invoice", MapUtil.mapped(voucher))));
        }
    }

    private void makePurchaseOrder(Location toLocation, Dept dept, PartyRole supplier, Contract contract, List<StockInventory> v1) {
        PartyRole employee = SpringManager.getBean(PartyRoleService.class).findByPartyAndRole(1, "Employee");
        Enumeration moveType = new Enumeration();
        moveType.setId("one");
        PurchaseOrder purchaseOrder = invoke("purchase.order.create1", mapper(
                "company", mapper("id", toLocation.getCompany().getId()),
                "dept", mapper("id", dept.getId()),
                "clerk", mapper("id", contract.getApproveUid().getId()),
                "supplier", mapper("id", supplier.getId()),
                "contract", mapper("id", contract.getId()),
                "cooperation", mapper("id", contract.getCooperation().getId()),
                "moveType", mapper("id", moveType.getId()),
                "location", mapper("id", toLocation.getId()),
                "note", "门店批量库存处理",
                "purchaseItems", v1.stream().map(sockInventory -> {
                    Map m = new HashMap();
                    m.put("product", mapper("id", sockInventory.getInventoryBatch().getProduct().getId()));
                    m.put("tax", mapper("id", sockInventory.getInventoryBatch().getTax().getId()));
                    m.put("uom", mapper("id", sockInventory.getInventoryBatch().getUom().getId()));
                    m.put("priceUnit", sockInventory.getInventoryBatch().getTaxCostPrice());
                    m.put("productUomQty", sockInventory.getIncrement());
                    return m;
                }).collect(Collectors.toList())));
        purchaseOrder.setState("confirmed");
        purchaseOrder.setApproveUid(employee);
        purchaseOrder.setDateApprove(new Date());

        purchaseOrder.getPurchaseItems().forEach(item -> {
            productAccountService.setProductAvailable(item.getProduct(), item.getPurchaseOrder().getLocation(),
                    item.getUom(), Math.abs(item.getProductUomQty()),
                    item.getPurchaseOrder().getInnerBusinessType(), item.getPurchaseOrder().getInnerBusinessKey(),
                    String.valueOf(item.getId()), item.getPurchaseOrder().getNote(), item.getPurchaseOrder().getCompany());
            productAccountService.setProductCustody(item.getProduct(), item.getPurchaseOrder().getLocation(),
                    item.getUom(), Math.abs(item.getProductUomQty()),
                    item.getPurchaseOrder().getInnerBusinessType(), item.getPurchaseOrder().getInnerBusinessKey(),
                    String.valueOf(item.getId()), item.getPurchaseOrder().getNote(), item.getPurchaseOrder().getCompany());
            item.delivery(item.getProductUomQty());
        });
        purchaseOrder.setShipped();
        purchaseOrder = SpringManager.getBean(PurchaseOrderRepository.class).saveAndFlush(purchaseOrder);

        Voucher voucher = invoke("voucher.create", mapper(
                "company", mapper("id", purchaseOrder.getCompany().getId()),
                "dept", mapper("id", purchaseOrder.getDept().getId()),
                "clerk", mapper("id", purchaseOrder.getClerk().getId()),
                "contract", mapper("id", purchaseOrder.getContract().getId()),
                "partner", mapper("id", purchaseOrder.getSupplier().getId()),
                "inventoryMode", purchaseOrder.getCooperation().getInventoryMode(),
                "accountingMethod", purchaseOrder.getCooperation().getAccountingMethod(),
                "origin", purchaseOrder.getId(),
                "originBusinessType", purchaseOrder.getInnerBusinessType(),
                "source", purchaseOrder.getId(),
                "sourceBusinessType", purchaseOrder.getInnerBusinessType(),
                "voucherItems", purchaseOrder.getPurchaseItems().stream().map(item -> {
                    Map m = new HashMap();
                    m.put("product", mapper("id", item.getProduct().getId()));
                    m.put("tax", mapper("id", item.getTax().getId()));
                    m.put("owner", mapper("id", item.getPurchaseOrder().getLocation().getCompany().getId()));
                    m.put("uom", mapper("id", item.getUom().getId()));
                    m.put("productQty", item.getProductUomQty());
                    m.put("priceUnit", item.getPriceUnit());
                    m.put("originItemId", String.valueOf(item.getId()));
                    m.put("sourceItemId", String.valueOf(item.getId()));
                    return m;
                }).collect(Collectors.toList())
        ));

        if (!("A00000".equals(supplier.getId())) && InventoryMode.IM_OWN.equals(voucher.getInventoryMode())) { /**生成帐单**/
            invoke("invoice.create", MapUtil.mapped(invoke("voucher.flow.invoice", MapUtil.mapped(voucher))));
        }
    }

    @Autowired
    private EntityManager em;
    @Autowired
    private InventoryBatchRepository inventoryBatchRepository;

    private List<Batch> findInventoryBatch(String companyId, String locationId, String productId) {
        List<Batch> batches = new ArrayList();
        Map<String, Object> params = new HashMap<>();
        params.put("companyId", companyId);
        params.put("locationId", locationId);
        params.put("productId", productId);
        String sql = "select inventory_id, balance_qty\n" +
                "  from (select company_id, location_id, supplier_id, product_id,\n" +
                "                cooperation_id, inventory_id, sum(product_qty) product_qty,\n" +
                "                decode(location_id, :locationId, 1, 0) priority,\n" +
                "                (select balance_qty - frost_qty\n" +
                "                    from acc_inventory_batch\n" +
                "                   where id = a.inventory_id) balance_qty\n" +
                "           from (select a.company_id,\n" +
                "                         GET_CK(a.dept_id, a.source_business_type, a.source) location_id,\n" +
                "                         a.voucher_type, a.source_business_type,\n" +
                "                         a.origin_business_type, c.product_qty,\n" +
                "                         c.inventory_cooperation_id cooperation_id,\n" +
                "                         c.inventory_supplier_id supplier_id, c.product_id,\n" +
                "                         c.inventory_id\n" +
                "                    from acc_voucher a, acc_voucher_item b,\n" +
                "                         acc_voucher_inventory c\n" +
                "                   where a.id = b.voucher_id\n" +
                "                     and a.id = c.voucher_id\n" +
                "                     and b.id = c.voucher_item_id\n" +
                "                     and a.voucher_type in ('SUPPLIER_PURCHASE')\n" +
                "                  union all\n" +
                "                  select a.company_id,\n" +
                "                         GET_CK(a.dept_id, a.source_business_type, a.source) location_id,\n" +
                "                         a.voucher_type, a.source_business_type,\n" +
                "                         a.origin_business_type, -1 * c.product_qty product_qty,\n" +
                "                         c.inventory_cooperation_id cooperation_id,\n" +
                "                         c.inventory_supplier_id supplier_id, c.product_id,\n" +
                "                         c.inventory_id\n" +
                "                    from acc_voucher a, acc_voucher_item b,\n" +
                "                         acc_voucher_inventory c\n" +
                "                   where a.id = b.voucher_id\n" +
                "                     and a.id = c.voucher_id\n" +
                "                     and b.id = c.voucher_item_id\n" +
                "                     and a.voucher_type in ('CUSTOMER_SALE')) a\n" +
                "          group by company_id, location_id, supplier_id, product_id,\n" +
                "                   cooperation_id, inventory_id)\n" +
                " where balance_qty <> 0\n" +
                "   and product_id = :productId\n" +
                "   and company_id = :companyId\n" +
                " order by priority desc";
        Query query = em.createNativeQuery(sql);
        if (params != null) {
            query.getParameters().stream().forEach(parameter -> {
                query.setParameter(parameter.getName(), params.get(parameter.getName()));
            });
        }

        query.unwrap(NativeQueryImpl.class)
                .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP)
                .getResultStream()
                .forEach(m -> {
                    long inventoryId = ((BigDecimal) ((Map) m).get("INVENTORY_ID")).longValue();
                    if (batches.stream().filter(batch -> ((InventoryBatch) batch.getEntity()).getId() == inventoryId).count() > 0) {
                        return;
                    }
                    InventoryBatch inventoryBatch = inventoryBatchRepository.findOne(inventoryId);
                    Batch batch = new Batch();
                    batch.setEntity(inventoryBatch);
                    double qty = inventoryBatch.getUom().computeQty(inventoryBatch.getBalanceQty(), inventoryBatch.getProduct().getUom(), true);
                    batch.setQty(qty);
                    batches.add(batch);
                });

        sql = "select id inventory_id, balance_qty\n" +
                "  from acc_inventory_batch\n" +
                " where (balance_qty - frost_qty) <> 0\n" +
                "   and product_id = :productId\n" +
                "   and company_id = :companyId";
        Query query1 = em.createNativeQuery(sql);
        if (params != null) {
            query1.getParameters().stream().forEach(parameter -> {
                query1.setParameter(parameter.getName(), params.get(parameter.getName()));
            });
        }
        query1.unwrap(NativeQueryImpl.class)
                .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP)
                .getResultStream()
                .forEach(m -> {
                    long inventoryId = ((BigDecimal) ((Map) m).get("INVENTORY_ID")).longValue();
                    if (batches.stream().filter(batch -> ((InventoryBatch) batch.getEntity()).getId() == inventoryId).count() > 0) {
                        return;
                    }
                    Batch batch = new Batch();
                    InventoryBatch inventoryBatch = inventoryBatchRepository.findOne(inventoryId);
                    batch.setEntity(inventoryBatch);
                    double qty = inventoryBatch.getUom().computeQty(inventoryBatch.getBalanceQty(), inventoryBatch.getProduct().getUom(), true);
                    batch.setQty(qty);
                    batches.add(batch);
                });

        return batches;
    }

    @Data
    public class StockInventory {
        private Stock stock;
        private InventoryBatch inventoryBatch;
        private double increment;

        public PartyRole getSupplier() {
            return inventoryBatch.getSupplier();
        }

        public Contract getContract() {
            return inventoryBatch.getContract();
        }
    }

    public Page<Map> findUsableQty(SimpleRequest simpleRequest) {
        JSONObject getJO = simpleRequest.getJO();
        JSONArray conditionArray = getJO.getJSONArray("condition");
        String locationId = "", productId = "", sceneId = "";
        if (getJO.get("key") != null) productId = getJO.getString("key");
        JSONObject domainObj = getJO.getJSONObject("domain");
        domainObj = domainObj == null?getJO.getJSONObject("group"):domainObj;

        List<Integer> hcbj = new ArrayList<>();
        List<String> wzly = new ArrayList<>();
        boolean sign = false;
        JSONArray filtersArray = domainObj.getJSONArray("filters");
        for (int i = 0, iLen = filtersArray.size(); i < iLen; i++) {
            JSONObject filtersObj = filtersArray.getJSONObject(i);
            String field = filtersObj.getString("field");
            String value = filtersObj.getString("value");
            if ("location".equals(field)) locationId = value;
            if ("sceneId".equals(field) && value.equals("HC000")) {
                hcbj.add(1);
                List<ProductGroup> productGroupList = SpringManager.getBean(ProductGroupRepository.class).findAll();
                productGroupList.forEach(productGroup -> wzly.add(productGroup.getId()));
            } else if ("sceneId".equals(field) && value.equals("HC002")) {
                sign = true;
                hcbj.add(0);
                hcbj.add(1);
                ProductGroup productGroup = SpringManager.getBean(ProductGroupRepository.class).findOne("50");
                wzly.add(productGroup.getId());
            }
        }

        for (int i = 0; (conditionArray != null && i < conditionArray.size()); i++) {
            JSONObject conditionObj = conditionArray.getJSONObject(i);
            String field = conditionObj.getString("field");
            String value = conditionObj.getString("value");
            if ("product".equals(field)) productId = value;
        }

        Page<Map> pageMap;
        if (productId.isEmpty()) {
            if(sign){
                pageMap = stockRepository.findUsableQty3(locationId, hcbj, wzly, PageRequest.of(getJO.getInteger("page"), getJO.getInteger("size")));
            } else {
                pageMap = stockRepository.findUsableQty(locationId, hcbj, wzly, PageRequest.of(getJO.getInteger("page"), getJO.getInteger("size")));
            }
        } else {
            if(sign){
                pageMap = stockRepository.findUsableQty4(locationId, productId, productId, hcbj, wzly, PageRequest.of(getJO.getInteger("page"), getJO.getInteger("size")));
            } else {
                pageMap = stockRepository.findUsableQty2(locationId, productId, productId, hcbj, wzly, PageRequest.of(getJO.getInteger("page"), getJO.getInteger("size")));

            }
        }
        return pageMap;
    }

    /**
     * 商品价格信息
     * @param simpleRequest 请求参数
     */
    public JSONObject queryProductPrice(SimpleRequest simpleRequest) {
        JSONObject param = simpleRequest.getJO();
        if(getPostId(simpleRequest).equals("A0000"))throw new RuntimeException("请勿使用管理员权限");
        JSONObject data = param.getJSONObject("node");
        String postId = simpleRequest.getPostId();
        Post post = SpringManager.getBean(PostRepository.class).findOne(postId);
        Dept dept = post.getDept();
        if (Objects.isNull(dept)) {
            throw new RuntimeException("未找到对应的门店信息,请检查角色权限");
        }
        PartyRole company = post.getCompany();
        Product product = SpringManager.getBean(ProductRepository.class).findOne(data.getString("PRODUCT_ID"));
        PartyRole platform = getPlatform(false,true, company,product);
        Map<String, String> map = MapUtil.mapper(
                "DJGCID","XS51",
                "MDID",dept.getId(),
                "PLID",product.getClassify().getId(),
                "SPID",product.getId(),
                "PZID",product.getBrand().getQuality() == null ? null : product.getBrand().getQuality().getCode(),
                "PPID",product.getBrand().getId(),
                "XSZZID",company.getId(),
                "GSID",company.getId(),
                // "FNKHID",param.getString("MDID"),
                //"MDLXID",Objects.isNull(dept.getDeptType())?null:dept.getDeptType().getId(),
                // "FNVIPJBID",param.getString("MDID"),
                // "FNVIPSFID",param.getString("MDID"),
                "CGZZID",platform.getId(),
                "JLDW",product.getUom().getName(),
                "YYMS",company.getParty().getCorporate().getOperation().getCode(),
                "SYGSID",platform.getId(),
                "SQID", param.getString("MDID"),
                "XYGSID",company.getId(),
                "NOT_SPXJD_CREATE","1"
        );

        Map<String, String> NewMap = MapUtil.mapper(
                "conditionStrategyId","XS51",
                "SYS_RQ",new Date(),
                "SYS_NO_CHECK","CAR_LICENSE",
                "DEPT_ID",dept.getId(),
                "CLASSIFY_ID",product.getClassify().getId(),
                "PRODUCT_ID",product.getId(),
                "QUALITY",product.getBrand().getQuality() == null ? null : product.getBrand().getQuality().getCode(),
                "PPID",product.getBrand().getId(),
                "COMPANY_ID",company.getId(),
                "SAL_COMPANY_ID",company.getId(),
                // "FNKHID",param.getString("MDID"),
                //"MDLXID",Objects.isNull(dept.getDeptType())?null:dept.getDeptType().getId(),
                // "FNVIPJBID",param.getString("MDID"),
                // "FNVIPSFID",param.getString("MDID"),
                "PUR_COMPANY_ID",platform.getId(),
                "PRODUCT_UOM_ID",product.getUom().getId(),
                "OPERATION",company.getParty().getCorporate().getOperation().getId()
//                "SYGSID",platform.getId(),
//                "SQID", param.getString("MDID")
//                "XYGSID",company.getId(),
//                "NOT_SPXJD_CREATE","1"
        );
        JSONObject returnData =new JSONObject();
        if (!switched){
            returnData = piManager.synErp("ipmVipService.getDjgc", map);

        }else {
            Object obj = this.invoke("condition.execConditionStrategy", NewMap);
            returnData.put("obj",obj);

        }
        JSONObject re1 = JSONObject.parseObject(returnData.getString("obj"));
        JSONObject resultObject = new JSONObject();
        resultObject.put("productId", product.getId());
        resultObject.put("productName", product.getName());
        resultObject.put("referTax", re1.getDoubleValue("P008"));
        resultObject.put("purchaseCost",re1.getDoubleValue("S950"));
        double fee = getSupplyChainManagementFee(dept.getCompany().getId(), product.getClassify().getId(), "");

        resultObject.put("supplyChainManagement", Arith.mul(re1.getDoubleValue("S950"),fee));
        resultObject.put("salePrice", re1.getDoubleValue("S901"));
        resultObject.put("operation", re1.get("OPERATION"));
        resultObject.put("floorPrice",re1.getDoubleValue("P005"));

        return resultObject;
    }
    /**
     * 获取供应链管理费
     *
     * @param companyId
     * @param classifyId
     * @return
     */
    public double getSupplyChainManagementFee(String companyId, String classifyId, String supplierId) {
        PartyRole company = SpringManager.getBean(PartyRoleRepository.class).findOne(companyId);
        Map map = MapUtil.mapper(
                "OPERATION", company.getParty().getCorporate().getOperation().getId(), "COMPANY_ID", companyId, "SUPPLIER_ID", supplierId, "CLASSIFY_ID", classifyId, "SYS_RQ", new Date(), "conditionStrategyId", "FW_GYL_SK"
        );
        Object obj = this.invoke("condition.execConditionStrategy", map);
        JSONObject result = new JSONObject(MapUtil.mapped(obj));
//        if ("1".equals(result.getString("sys_break"))){
//            throw new RuntimeException("未成功获取价格！");
//        }
//        if (!companyId.equals(result.getString("COMPANY_ID"))){
//            throw new RuntimeException(String.format("取策略异常！传入公司[%s]返回公司[%s]", companyId, result.getString("COMPANY_ID")));
//        }
        return result.getDoubleValue("T001");
    }
    /**
     * @param a 是否定损
     * @param company 所属公司
     * @param product 商品
     * @return 返回数据
     */
    public PartyRole getPlatform(boolean a,boolean b, PartyRole company, Product product){
        boolean c ;
        boolean d = true;
        try {
            c = company.getParty().getCorporate().isWantInvoice();
        }catch (Exception e){
            throw new RuntimeException("查找门店对应公司是否开票失败，请检查是否配置");
        }
        if(product.getClassify() == null || product.getClassify().getId() == null){
            throw new RuntimeException("商品主数据定义不完整（品类），商品：" + product.getName());
        }
        try {
            d = SpringManager.getBean(CategorySupplyRangeService.class).checkInRange(product.getClassify(), product.getBrand());
        }catch (Exception e){
            throw new RuntimeException("innerMistake:查找品类直供范围有误，请检查");
        }
        return getPlatform(a,b,c,d);
    }
    /**
     *
     * @param a  是否定损 true 是
     * @param b  新旧系统 true 新
     * @param c  是否开票 true 开
     *  d  直供范围 true 直供内 (2020-06-17 zdz要求去除品类直供,18:要求取价格需直供，不取价格不要求直供)
     */
    private PartyRole getPlatform(boolean a,boolean b,boolean c,boolean d){
        String id = CONST_FNCOMMUNALSERVICE_PLATFORM_1001;
        if(!a && b && !c &&!d ){
            id = CONST_FNCOMMUNALSERVICE_PLATFORM_1007;
        }
        PartyRole partyRole;
        try {
            partyRole = SpringManager.getBean(PartyRoleService.class).findOne(id,"Company");
            if(partyRole == null){
                throw new Exception("");
            }
        }catch (Exception e){
            throw new RuntimeException("未找到对应的平台，平台编码：" + id);
        }
        return partyRole;
    }

    /** 查询库存 [可用数-冻结] 大于0的数据 */
    public Page<Stock> findAvailInventoryQty(SimpleRequest request) {
        JSONObject getJO = request.getJO();
        int page = getJO.get("page") == null?0:Integer.parseInt(getJO.get("page").toString()) - 1;
        int size = getJO.get("size") == null?50:Integer.parseInt(getJO.get("size").toString());

        String productId = "";
        if (getJO.getJSONObject("node") != null) {
            productId = getJO.getJSONObject("node").getJSONObject("product").getString("id");
        } else {
            productId = getJO.getJSONObject("data").getJSONObject("node").getJSONObject("product").getString("id");
        }
        return stockRepository.findAvailInventoryQty(productId, productId, PageRequest.of(page, size));
    }
}

















